package com.blue.base.common.utils.json;

import com.alibaba.fastjson.JSON;
import com.google.gson.*;
import com.google.gson.reflect.TypeToken;
import org.springframework.util.StringUtils;

import javax.servlet.ServletResponse;
import java.lang.reflect.Type;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Json工具类
 *
 * @author yidasanqian
 */
public final class JsonUtil {
    private static Gson gson = null;

    static {
        builder();
    }

    private JsonUtil() {
        // no-op, just to avoid new instance.
    }

    private static void builder() {
        LongSerializer serializer = new LongSerializer();
        BigIntegerSerializer bigIntegerSerializer = new BigIntegerSerializer();
        gson = new GsonBuilder().setDateFormat("yyyy-MM-dd HH:mm:ss")
                //添加BigInteger Long long 类型数据转String返回前端
                .registerTypeAdapter(BigInteger.class, bigIntegerSerializer)
                .registerTypeAdapter(long.class, serializer)
                .registerTypeAdapter(Long.class, serializer)
                .registerTypeAdapter(ServletResponse.class, new ServletResponseAdapter())
                .create();
    }

    public static synchronized Gson newInstance() {
        if (gson == null) {
            builder();
        }
        return gson;
    }

    public static String toJson(Object obj) {
        return gson.toJson(obj);
    }

    public static <T> T toBean(String json, Class<T> clz) {
        return gson.fromJson(json, clz);
    }

    public static <T> T toBean(Object sourceObject, Class<T> targetClass) {
        return gson.fromJson(toJson(sourceObject), targetClass);
    }

    public static <T> Map<String, T> toMap(String json, Class<T> clz) {
        Map<String, JsonObject> map = gson.fromJson(json, new TypeToken<Map<String, JsonObject>>() {
        }.getType());
        Map<String, T> result = new HashMap<>(8);
        for (Map.Entry<String, JsonObject> entry : map.entrySet()) {
            result.put(entry.getKey(), gson.fromJson(entry.getValue(), clz));
        }
        return result;
    }

    public static Map<String, Object> toMapUseFastJson(String json) {
        if (StringUtils.isEmpty(json)) {
            return new HashMap<>(1);
        }
        return JSON.parseObject(json);
    }

    public static Map<String, Object> toMap(String json) {
        return gson.fromJson(json, new TypeToken<Map<String, Object>>() {
        }.getType());
    }

    public static <T> List<T> toList(String json, Class<T> targetClass) {
        JsonArray array = new JsonParser().parse(json).getAsJsonArray();
        List<T> list = new ArrayList<>();
        for (final JsonElement elem : array) {
            list.add(gson.fromJson(elem, targetClass));
        }
        return list;
    }

    public static <T> List<T> toList(Object sourceObject, Class<T> clz) {
        return toList(toJson(sourceObject), clz);
    }

    private static class ServletResponseAdapter implements JsonSerializer<ServletResponse> {
        @Override
        public JsonElement serialize(ServletResponse servletResponse, Type type,
                                     JsonSerializationContext jsonSerializationContext) {
            return null;
        }
    }

    private static class LongSerializer implements JsonSerializer<Long> {
        @Override
        public JsonElement serialize(Long src, Type typeOfSrc, JsonSerializationContext context) {
            if (src != null) {
                String strSrc = src.toString();
                if (strSrc.length() > 15) {
                    return new JsonPrimitive(strSrc);
                }
            }
            return new JsonPrimitive(src);
        }
    }

    private static class BigIntegerSerializer implements JsonSerializer<BigInteger> {
        @Override
        public JsonElement serialize(BigInteger src, Type typeOfSrc, JsonSerializationContext context) {
            if (src != null) {
                String strSrc = src.toString();
                if (strSrc.length() > 15) {
                    return new JsonPrimitive(strSrc);
                }
            }
            return new JsonPrimitive(src);
        }
    }
}
